home *** CD-ROM | disk | FTP | other *** search
- program MenuBuild;
-
- imports MenuUtils from MenuUtils;
- imports Memory from Memory;
- imports System from System;
- imports FileSystem from FileSystem;
- imports CmdParse from CmdParse;
- imports Perq_String from Perq_String;
-
- { Abstract: This program build a menu structure in a user defined
- data segment. The data segment is written to a user specified
- .MSEG file.
- Such .MSEG files may subsequently be utilized by the MenuUtils.GetMenu
- procedure to load the menues for a given application in a high-speed
- fashion. ( Using MultiRead. )
-
- In parallel with the generation of the data segment, a .HLP-file is
- generated, which will contain the helptext from the menu text file.
- The .MSEG-file will contain blocknumbers referencing this .HLP-file,
- and the .HLP-file will NOT be loaded when the menues are loaded by the
- application, just read for the wanted information when HELP is requested
- from any menu.
-
- Usage: BuildMenu <input .MENU file>
- [~ <output .MSEG file>[,<output .HLP file ]
-
- }
-
- exception FullMenuSeg; { Will be raised if menu structure needs more than
- 32 K words }
- exception InvHelpFile; { Will be raised if any of the filenames given }
- exception InvSegFile; { are invalid (or nonexistent input file) }
- exception InvMenuFile;
-
- exception BadArgs;
-
- VAR
- Root : pMenuEntry;
- Mnu, MSeg, Help : PathName;
- Comm : CString;
- IsSwitch : Boolean;
- Inputs, Outputs : pArgRec;
- Switches : pSwitchRec;
- Err : String;
- Sep : Char;
-
- procedure MakeMenues( MenuFName, SegFName, HelpFName : PathName );
-
- VAR MenuFile : Text;
- SegF,HelpF : FileID;
- Blk, Bits : Integer;
- Line : String;
- LineNo : Integer;
- Indent : Integer;
- ShowMenues : boolean;
-
- HelpFree : HelpAddress;
-
- MenuSeg : SegmentNumber;
- FreePtr : MMPointer;
-
- DiskBuff : pDirBlk;
-
-
- procedure WriteSegment( SegFName: PathName;
- EndPtr: MMPointer);
- var NumBlocks, i : integer;
- SegF : FileID;
- begin
- NumBlocks := (EndPtr.Offset+255) div 256;
- SegF := FSEnter( SegFName );
- if SegF=0 then raise InvSegFile;
- for i := 0 to NumBlocks -1 do
- FSBlkWrite( SegF, i, MakePtr( EndPtr.Segmen, i*256, pDirBlk ));
- FSClose( SegF, NumBlocks, (EndPtr.Offset mod 256)*16 );
- end;
-
-
- procedure CreateHelpFile( HelpFName: PathName );
- begin
- HelpF := FSEnter( HelpFName );
- if HelpF=0 then raise InvHelpFile;
- with HelpFree do begin
- BlockNo := 0;
- Offset := 0;
- end;
- new( DiskBuff );
- end;
-
- procedure PutInBuffer( c : char );
- begin
- with HelpFree do begin
- DiskBuff^.ByteBuffer[ Offset ] := ord(c);
- Offset := Offset + 1;
- if Offset>511 then begin
- FSBlkWrite( HelpF, BlockNo, DiskBuff );
- Offset := 0;
- BlockNo := BlockNo + 1;
- end;
- end;
- end;
-
- procedure PutHelp( Txt : String );
- var I:integer;
- begin
- for I := 1 to length( Txt ) do
- PutInBuffer( Txt[I]);
- PutInBuffer( chr(13) );
- end;
-
-
- procedure CloseHelpFile;
- begin
- with HelpFree do begin
- if HelpFree.Offset>0 then begin { last buffer partially full }
- FSBlkWrite( HelpF, BlockNo, DiskBuff );
- FSClose( HelpF, BlockNo+1, Offset*8 );
- end else { last buffer is empty }
- FSClose( HelpF, BlockNo, 0 );
- end;
- end;
-
-
- procedure Allocate( s : integer );
- begin
- if (MMMaxExtSize div 2) > ((FreePtr.offset+S+255) div 256) then
- FreePtr.Offset := FreePtr.Offset + S
- else
- raise FullMenuSeg;
- end;
-
-
- function NewMenuEntry( NType : NodeType; NumComm : integer ):pMenuEntry;
- var ret : pMenuEntry;
- fixed : integer;
- begin
- Fixed := WordSize( HelpAddress )+
- WordSize( String )+ WordSize( NodeType);
- Ret := MakePtr( FreePtr.Segmen, FreePtr.Offset, pMenuEntry );
- case NType of
- ParmNode: Allocate( Fixed );
- EndNode : Allocate( Fixed );
- MenuNode: Allocate( Fixed + WordSize( pNameDesc )
- + NumComm*WordSize( pMenuEntry ) );
- end;
- ret^.Node := NType;
- NewMenuEntry := ret;
- end;
-
-
- function NewNameDesc( NumComm : integer ):pNameDesc;
- var ret:pNameDesc;
- begin
- Ret := MakePtr( FreePtr.Segmen, FreePtr.Offset, pNameDesc );
- Allocate( WordSize( Integer ) + (NumComm+1)*WordSize( S25 ) );
- Ret^.NumCommands := NumComm;
- NewNameDesc := ret;
- end;
-
-
- function GetMenu : pMenuEntry;
- VAR ME : pMenuEntry;
- NC : integer;
- CI : integer;
- begin
- indent := indent+4;
- readln( MenuFile, NC );
- ReadLn( MenuFile, Line );
-
- { determine what kind of a node has been encountered }
- if NC=0 then
- ME := NewMenuEntry( EndNode, 0 )
- else
- if NC<0 then
- ME := NewMenuEntry( ParmNode, 0 )
- else
- ME := NewMenuEntry( MenuNode, NC+1 );
-
-
- { build node }
- with ME^ do begin
- if Node=MenuNode then
- begin
- MPtr := NewNameDesc( NC+1 );
- if Line<>'>' then begin
- MPtr^.Header := Line;
- ReadLn( MenuFile, Line );
- end else
- MPtr^.Header := '';
- MPtr^.Commands[1] := 'HELP'; { Always a HELP entry }
- end;
- if Line<>'>' then begin
- Prompt := Line;
- ReadLn( MenuFile, Line );
- end else
- Prompt := '';
-
- Help := HelpFree;
- while line<>'>' do begin
- PutHelp( Line );
- ReadLn( MenuFile, Line );
- end;
- PutHelp( Line );
-
- if Node=MenuNode then
- for CI := 2 to NC+1 do begin
- ReadLn( MenuFile, Line );
- if ShowMenues then
- writeln( '':indent, Line );
- {$range-}
- MPtr^.Commands[ CI ] := Line;
- NextLevel[ CI ] := GetMenu;
- {$range+}
- end;
- end;
-
- GetMenu := ME;
- Indent := Indent-4;
- end;
-
-
- begin
- { Open menu source file }
- if FSLookUp( MenuFName, Blk, Bits )=0 then
- raise InvMenuFile
- else begin
- reset( MenuFile, MenuFName);
-
- { Allocate a BIG segment to build menues in }
- { Use half of max. size to avoid trouble with }
- { two's complement integer arithmetic }
- CreateSegment( MenuSeg, MMMaxExtSize div 2, 1, MMMaxExtSize div 2 );
- with FreePtr do begin
- Offset := WordSize( Integer );
- Segmen := MenuSeg;
- end;
-
- CreateHelpFile( HelpFName );
- LineNo := 0;
- Indent := 0;
- ReadLn( MenuFile, Line );
- ShowMenues := Line<>'';
-
- { Now go for it!! }
- Root := GetMenu;
- CloseHelpFile;
- WriteSegment( SegFName, FreePtr );
- end;
- end;
-
-
- function StripOff( InStr, Tail : Pstring ):Pstring;
- { Strip <Tail> from <InStr> if the last characters of <InStr> matches <Tail> }
- var InL,TailL : integer;
- T1, T2 : String;
- begin
- InL := Length( InStr );
- while InStr[InL]=' ' do begin
- InL := InL - 1;
- Adjust( InStr, InL );
- end;
- TailL := Length( Tail );
- if TailL>InL then begin
- StripOff := InStr
- end else begin
- T1 := SubStr( InStr,InL+1-TailL,TailL );
- ConvUpper( T1 );
- T2 := Tail;
- ConvUpper( T2 );
- if T1=T2 then begin
- StripOff := SubStr( InStr, 1, InL-TailL )
- end else begin
- StripOff := InStr;
- end;
- end;
- end;
-
-
- procedure ParseArgs;
-
- handler InvMenuFile;
- begin
- writeln('Menu file: ',Mnu,' is invalid name or does not exist!');
- exit( ParseArgs );
- end;
-
- handler InvSegFile;
- begin
- writeln('Segment file name: ',Mseg,' is invalid name!');
- exit( ParseArgs );
- end;
-
- handler InvHelpFile;
- begin
- writeln('Help file name: ',Help,' is invalid name!');
- exit( ParseArgs );
- end;
-
- handler BadArgs;
- begin
- exit( ParseArgs );
- end;
-
- begin
- Sep := NextId( Comm, isSwitch );
- if ParseCmdArgs( Inputs, Outputs, Switches, Err ) then begin
- Mnu := '';
- Mseg := '';
- Help := '';
-
- if Inputs<>NIL then Mnu := StripOff( Inputs^.Name, '.MENU' );
- if Outputs<>NIL then begin
- Mseg := StripOff( Outputs^.Name, '.MSEG' );
- if Outputs^.Next<>NIL then begin
- Help := StripOff( Outputs^.Next^.Name, '.HLP' );
- end;
- end;
- if Mnu='' then
- Mnu := StripOff( LastFileName, '.MENU' );
- if Mnu='' then
- if Mseg='' then begin
- if Help='' then begin
- writeln('No filename given!');
- Raise BadArgs;
- end else begin
- Mseg := Help;
- Mnu := Help;
- end;
- end else begin
- Mnu := Mseg;
- end;
- if Mseg='' then
- Mseg := Mnu;
- if Help='' then
- Help := Mseg;
-
- Mnu := Concat( Mnu, '.MENU' );
- Mseg := Concat( Mseg, '.MSEG' );
- Help := Concat( Help, '.HLP' );
- Writeln( 'Reading: ',Mnu, ',');
- Writeln( ' ==> ', MSeg, ', ', Help );
- MakeMenues( Mnu, Mseg, Help );
- end
- else begin
- writeln(Err);
- writeln;
- writeln
- ('Usage: MenuBuild <.MENU file> [~<.MSEG file> [,<.HLP file>] ]');
- end;
- end;
-
- begin
- Inputs := NIL;
- Outputs := NIL;
- Switches := NIL;
- ParseArgs;
- DstryArgRec( Inputs );
- DstryArgRec( Outputs );
- DstrySwitchRec( Switches );
- end.
-